import { tuple } from '@gnlab/utils'
import { message } from 'antd'
import { TOKEN_EVENT_NAME } from '@/apps-transfer-token/definition'
import config from '@/config'
import { useStreams } from '@/lib/utils'
import services from '@/services'
import { type AuthMethod, LoginStatus } from '@/services/auth'

/**
 * 取得 / 设置登录方式
 */
const METHOD_KEY = 'auth-method'

export function useLoginMethod() {
  const methods = config.USABLE_AUTH_METHODS as AuthMethod[]

  const [method, setMethod] = useState(() => {
    const memMethod = (localStorage.getItem(METHOD_KEY) ?? '') as AuthMethod
    return (methods.includes(memMethod) ? memMethod : config.USABLE_AUTH_METHODS[0]) as AuthMethod
  })

  const switchMethod = useCallback((_method: AuthMethod) => {
    setMethod(_method)
    localStorage.setItem(METHOD_KEY, _method)
  }, [])

  return tuple(methods, method, switchMethod)
}

/**
 * 封装流量超市登录相关界面逻辑
 */
export function useAppsLogin() {
  const { apps } = useMemo(() => services.auth, [])

  // 有值说明已取得 token，进入验证状态
  const [token, setToken] = useState<string | null>(null)
  const confirming = token !== null

  // 流量超市登录 URL
  const transTokenUrl = `${location.origin}${location.pathname}apps-transfer-token/index.html`
  const loginUrl = `${
    config.ACCOUNT_BASE_URL
  }/login?source=quntool&redirect_uri=${encodeURIComponent(transTokenUrl)}`

  useEffect(() => {
    function listener(msg: MessageEvent<{ type: string; token: string }>) {
      if (msg.data.type === TOKEN_EVENT_NAME && msg.data.token) {
        const token = msg.data.token
        setToken(token)
        apps.gotToken(token)
      }
    }
    window.addEventListener('message', listener)
    return () => window.removeEventListener('message', listener)
  }, [])

  // 取得 token 后若验证失败，可调用此函数清除登录信息，重新登录或用其他号登录
  const logout = useCallback(async () => {
    if (token === null) return
    const res = await services.auth.apps.logout(token)
    if (!res.success) void message.warning(res.error.message)
    setToken('')
  }, [token])

  const [loginInfo] = useStreams(services.auth.info$)
  const failedMessage = loginInfo.status === LoginStatus.LoginFailed ? loginInfo.message : ''

  return { confirming, message: failedMessage, loginUrl, logout }
}
